#include "irprinter.h"

#include <functional>
#include <iostream>
#include <unordered_set>

#include "ir.h"
#include "irfunction.h"

using namespace Utils;

void Debug(IRFunction* func) {
    std::cout << DEF "\n" << func->name << ": ";
    for (auto v : func->args) v->Print(), std::cout << " ";
    std::cout << "\n";

    func->globalEffects.Print();
    std::cout << DEF "Used: ";
    for (auto [_, x] : func->usedGlobalVars) {
        x.Print(), std::cout << " ";
    }
    std::cout << DEF "\nArg: ";
    for (auto x : func->argMemEffects) {
        std::cout << x << " ";
    }
    std::cout << "\n";

    int count = 0;
    std::unordered_set<IRBlock*> vis;
    std::function<void(IRBlock*)> visit = [&](IRBlock* cur) {
        Assert(cur->GetTerminator(), "IRBlock should end with a terminator");
        if (vis.count(cur)) return;
        vis.insert(cur);
        cur->name = ".L" + std::to_string(++count);
        for (auto nxt : cur->GetNext()) visit(nxt);
    };
    visit(func->entry);

    vis.clear();
    visit = [&](IRBlock* cur) {
        Assert(cur->GetTerminator(), "IRBlock should end with a terminator");
        if (vis.count(cur)) return;
        vis.insert(cur);
        cur->Print();
        for (auto nxt : cur->GetNext()) visit(nxt);
    };
    visit(func->entry);
}

void* IRPrinter::Run(void* input) {
    auto module = (IRModule*)input;
    for (auto [var, sym] : module->globalVars) {
        std::cout << DEF "\n" << sym->name << ": ";
        std::cout << sym->allocMem << ", ";
        var->Print();
        std::cout << "\n";
    }
    for (auto func : module->globalFuncs) {
        Debug(func);
    }
    return input;
}
